
package com.trydofor.id.sample.jdbc;

import java.io.InputStream;
import java.net.InetSocketAddress;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;

import com.trydofor.id.a9id.A9ID;
import com.trydofor.id.body.shell.ShellQueryBody;
import com.trydofor.id.core.A9Maker;
import com.trydofor.id.lazy.LazyA9Maker;
import com.trydofor.id.xnet.A9idNetLoader;
import com.trydofor.id.xnet.ConfBuilder;
import com.trydofor.id.xnet.NetServer;

/**
 * @author : Shi Rongjiu (www.trydofor.com)
 */
public class Start {
    
    private static final Logger LOGGER   = LoggerFactory.getLogger(Start.class);
    private static final String HOST     = "127.0.0.1";
    private static final int    PORT     = 3000;
    private static final int    AUTH     = 9;
    private static final String MAKER    = "A9ID-1";
    private static final int    MAKER_ID = 9;
    private static final int    COUNT    = 100;
    
    private NetServer startServer() throws Exception {
        NetServer ns = new NetServer();
        InputStream fl = Start.class.getResourceAsStream("conf/extcmd.xml");
        List<ShellQueryBody> cmds = ConfBuilder.buildCmd(fl);
        for (ShellQueryBody cmd : cmds) {
            ns.execCommand(cmd);
        }
        ns.start(new InetSocketAddress(HOST, PORT));
        return ns;
    }
    
    private A9Maker<A9ID> startNetMaker() {
        A9idNetLoader l = new A9idNetLoader(HOST, PORT, AUTH);
        l.setTimeout(10000); // 10ms
        l.setCount(COUNT);
        l.setMaker(MAKER);
        A9Maker<A9ID> m = new LazyA9Maker<A9ID>(l, 100);
        return m;
    }
    
    private void insertOneA9id(DataSource ds, A9ID id) throws SQLException {
        JdbcTemplate jt = new JdbcTemplate(ds);
        jt.execute("INSERT INTO LONG_MAKER(MAKER_ID, MAKER_NAME) VALUES (" + MAKER_ID + ", '" + MAKER + "')");
    }
    
    private void insertMoreA9id(DataSource ds, final List<A9ID> ids) throws SQLException {
        if (ids == null || ids.isEmpty()) return;
        JdbcTemplate jt = new JdbcTemplate(ds);
        jt.batchUpdate("INSERT INTO LONG_VALUE(LONG_MAKER, LONG_VALUE) VALUES (?,?)",
                new BatchPreparedStatementSetter() {
                    
                    @Override
                    public void setValues(PreparedStatement ps, int i) throws SQLException {
                        A9ID id = ids.get(i);
                        ps.setInt(1, MAKER_ID);
                        ps.setLong(2, id.longValue());
                    }
                    
                    @Override
                    public int getBatchSize() {
                        return ids.size();
                    }
                });
    }
    
    /**
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        final Start s = new Start();
        final NetServer server = s.startServer();
        final A9Maker<A9ID> maker = s.startNetMaker();
        final DataSource ds = (DataSource) server.getWareFactory().getInstance("datasource/insert");
        
        final int partCount = 2;
        final int countEach = 5000000;
        final int stepEach = 1000;
        final int threadEach = 10;
        
        final ExecutorService es = Executors.newFixedThreadPool(threadEach * partCount);
        for (int i = 0; i < threadEach; i++) {
            es.submit(new Runnable() {
                
                @Override
                public void run() {
                    long start = System.currentTimeMillis();
                    Thread t = Thread.currentThread();
                    for (int i = 1; i <= countEach; i++) {
                        A9ID id = maker.make();
                        try {
                            s.insertOneA9id(ds, id);
                        }
                        catch (SQLException e) {
                            LOGGER.error("id=" + id, e);
                        }
                        if (i % stepEach == 0) {
                            System.out.println(t + ".one-> " + i + " costs "
                                               + (System.currentTimeMillis() - start) + "ms");
                            start = System.currentTimeMillis();
                        }
                    }
                    System.out.println("=== ");
                }
            });
            //
            es.submit(new Runnable() {
                
                @Override
                public void run() {
                    long start = System.currentTimeMillis();
                    List<A9ID> ids = new ArrayList<A9ID>(stepEach);
                    Thread t = Thread.currentThread();
                    for (int i = 1; i <= countEach; i++) {
                        A9ID id = maker.make();
                        ids.add(id);
                        if (i % stepEach == 0) {
                            try {
                                s.insertMoreA9id(ds, ids);
                            }
                            catch (SQLException e) {
                                LOGGER.error("i=" + i, e);
                            }
                            System.out.println(t + ".more-> " + i + " (" + ids.size() + ") costs "
                                               + (System.currentTimeMillis() - start) + "ms");
                            ids.clear();
                            start = System.currentTimeMillis();
                        }
                    }
                    if (!ids.isEmpty()) {
                        try {
                            s.insertMoreA9id(ds, ids);
                        }
                        catch (SQLException e) {
                            LOGGER.error("", e);
                        }
                        System.out.println(t + ".more-> " + ids.size() + " costs "
                                           + (System.currentTimeMillis() - start) + "ms");
                    }
                }
            });
        }
        
        es.shutdown();
        Thread.currentThread().join();
    }
}
